package org.hfy.collections.helper;

import org.hfy.Constants;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: Takagi
 * @date: 2023/4/23
 */
public class ItemSet {
    public Set<Production> coreItemSet = new HashSet<>();
    public Set<Production> nonCoreItemSet = new HashSet<>();

    /*
     * @Author Takagi
     * @Description: 为所有项目添加一个符号
     * @date: 2023/5/13
     * @param symbol
     * @return
     **/
    public void addSymbolAtItemLast(SymbolString string) {
        for (Symbol symbol : string.getSymbolList()) {
            this.coreItemSet = coreItemSet.stream().map(production -> {
                Production newProduction = new Production();
                newProduction.left = production.left;
                newProduction.right = production.right;
                newProduction.right.addSymbol(symbol);
                return newProduction;
            }).collect(Collectors.toSet());
            this.nonCoreItemSet = nonCoreItemSet.stream().map(production -> {
                Production newProduction = new Production();
                newProduction.left = production.left;
                newProduction.right = production.right;
                newProduction.right.addSymbol(symbol);
                return newProduction;
            }).collect(Collectors.toSet());
        }
    }

    /*
     * @Author Takagi
     * @Description: 获取第一个核心项目
     * @date: 2023/5/13
     * @param
     * @return * @return Production
     **/
    public Production getFirstCoreItem() {
        if (coreItemSet.size() == 0) return null;
        return coreItemSet.iterator().next();
    }

    /*
     * @Author Takagi
     * @Description: 是否为接受状态
     * @date: 2023/5/13
     * @param extendGrammar
     * @return * @return boolean
     **/
    public boolean isAcceptState(Symbol extendGrammar) {
        return isReducedState() && coreItemSet.size() == 1 && coreItemSet.iterator().next().left.equals(extendGrammar);
    }

    /*
     * @Author Takagi
     * @Description: 是否为归约状态
     * @date: 2023/5/13
     * @param
     * @return * @return boolean
     **/
    public boolean isReducedState() {
        return this.nonCoreItemSet.size() == 0;
    }

    /*
     * @Author Takagi
     * @Description: 是否为移进状态
     * @date: 2023/5/13
     * @param
     * @return * @return boolean
     **/
    public boolean isShiftState() {
        return !isReducedState();
    }

    /*
     * @Author Takagi
     * @Description: 获取所有的归约项目
     * @date: 2023/4/26
     * @param
     * @return * @return Set<Symbol>
     **/
    public Set<Production> getAllReducedItem() {
        Set<Production> result = new HashSet<>();
        for (Production production : this.getAllItem()) {
            if (production.getItemNextSymbol().equals(new Symbol(Constants.EOF))) {
                result.add(production);
            }
        }
        return result;
    }

    /*
     * @Author Takagi
     * @Description: 获取核心项目集的产生式个数
     * @date: 2023/4/25
     * @param
     * @return * @return int
     **/
    public int getCoreItemSize() {
        return this.coreItemSet.size();
    }

    /*
     * @Author Takagi
     * @Description: 将 item 添加到核心项目中
     * @date: 2023/4/25
     * @param item
     * @return
     **/
    public void addCoreItem(Production item) {
        this.coreItemSet.add(item);
    }

    /*
     * @Author Takagi
     * @Description: 获取所有的项目
     * @date: 2023/4/25
     * @param
     * @return * @return Set<Production>
     **/
    public Set<Production> getAllItem() {
        Set<Production> allItem = new HashSet<>();
        allItem.addAll(coreItemSet);
        allItem.addAll(nonCoreItemSet);
        return allItem;
    }

    /*
     * @Author Takagi
     * @Description: 获取所有去除 LR 符号的项目
     * @date: 2023/5/13
     * @param
     * @return * @return Set<Production>
     **/
    public Set<Production> getAllItemIgnoreLRFlag() {
        return this.getAllItem().stream().map(Production::getProductionIgnoreItem).collect(Collectors.toSet());
    }

    /*
     * @Author Takagi
     * @Description: 获取项目集中可能的所有输入
     * @date: 2023/4/25
     * @param
     * @return * @return Set<Symbol>
     **/
    public Set<Symbol> getInputSymbols() {
        Set<Symbol> inputSymbol = new HashSet<>();
        for (Production production : this.getAllItem()) {
            Symbol symbol = production.right.getItemNextSymbol();
            if (symbol != null && !symbol.content.equals(Constants.SEARCH_SYMBOL_SEPARATOR)) {
                inputSymbol.add(symbol);
            }
        }
        return inputSymbol;
    }

    /*
     * @Author Takagi
     * @Description: 获取输入 input 后的项目集
     * @date: 2023/4/25
     * @return * @return ItemSet
     **/
    public ItemSet move(Symbol input) {
        ItemSet output = new ItemSet();
        for (Production production : this.getAllItem()) {
            Symbol symbol = production.getItemNextSymbol();
            // 项目右侧的符号与 input 相同，接收输入
            if (symbol.equals(input)) {
                Production nextItemProduction = production.getNextItem();
                if (nextItemProduction != null) {
                    output.addCoreItem(nextItemProduction);
                }
            }
        }
        if (output.getCoreItemSize() == 0) return null;
        return output;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof ItemSet) {
            return ((ItemSet) other).getAllItem().equals(this.getAllItem());
        }
        return false;
    }

    public String itemSetToString(Set<Production> itemSet) {
        if (itemSet.size() == 0) return "null";
        StringBuilder res = new StringBuilder();
        for (Production production : itemSet) {
            res.append(production.toString()).append("\n");
        }
        return res.toString();
    }

    @Override
    public String toString() {
        return String.format("core item set :\n%s\nnon core item set :\n%s", itemSetToString(coreItemSet), itemSetToString(nonCoreItemSet));
    }
}
